#    pythonequations is a collection of equations expressed as Python classes
#    Copyright (C) 2008 James R. Phillips
#    2548 Vera Cruz Drive
#    Birmingham, AL 35235 USA
#    email: zunzun@zunzun.com
#
#    License: BSD-style (see LICENSE.txt in main source directory)
#    Version info: $Id: Trigonometric.py 329 2011-10-16 10:56:05Z zunzun.com $

import pythonequations, pythonequations.EquationBaseClasses, pythonequations.ExtraCodeForEquationBaseClasses
import numpy
numpy.seterr(all = 'raise') # numpy raises warnings, convert to exceptions to trap them


class Sinc2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Cardinal Sine (sinc)"
    _HTML = "y = a * sin(x) / x"
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] * _id[_cwo[0]+i] / _id[_cwo[1]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_SinX(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(x_in) / x_in;\n"
        return s



class SincTransform2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Cardinal Sine (sinc) Transform"
    _HTML = "y = a * sin(bx + c) / (bx + c)"
    coefficientDesignatorTuple = ('a','b','c')
    function_cpp_code = 'temp = coeff[0] * sin(coeff[1] * _id[_cwo[0]+i] + coeff[2]) / (coeff[1] * _id[_cwo[0]+i] + coeff[2]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(b * x_in + c) / (b * x_in + c);\n"
        return s



class SincSquared2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Cardinal Sine Squared (sinc squared)"
    _HTML = "y = a * (sin(x))<sup>2</sup> / x"
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] * pow(_id[_cwo[0]+i], 2.0) / _id[_cwo[1]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_SinX(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * pow(sin(x_in), 2.0) / x_in;\n"
        return s



class SincTransformSquared2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Cardinal Sine Squared (sinc squared) Transform"
    _HTML = "y = a * (sin(bx + c))<sup>2</sup> / (bx + c)"
    coefficientDesignatorTuple = ('a','b','c')
    function_cpp_code = 'temp = coeff[0] * pow(sin(coeff[1] * _id[_cwo[0]+i] + coeff[2]), 2.0) / (coeff[1] * _id[_cwo[0]+i] + coeff[2]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * pow(sin(b * x_in + c), 2.0) / (b * x_in + c);\n"
        return s



class SineA2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Sine A [radians]"
    _HTML = "y = a * sin(x)"
    LinearSSQSolverFlag = 1
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] * _id[_cwo[0]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_SinX(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(x_in);\n"
        return s



class SineB2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Sine B [radians]"
    _HTML = "y = a * sin(b*x)"
    coefficientDesignatorTuple = ("a", "b")
    requiresCoefficientBoundsCheckWhenFitting = 1
    function_cpp_code = 'temp = coeff[0] * sin(coeff[1] * _id[_cwo[1]+i]);'


    def Initialize(self):
        pythonequations.EquationBaseClasses.Equation2D.Initialize(self)

        try:
            nobs = len(self.IndependentDataArray[0])
            maxVal = max(self.IndependentDataArray[0])
            minVal = min(self.IndependentDataArray[0])
            self.upperCoefficientBoundsArray[1] = (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
            self.lowerCoefficientBoundsArray[1] = -1.0 * (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
        except:
            pass

    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(b * x_in);\n"
        return s



class SineC2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Sine C [radians]"
    _HTML = "y = a * sin(bx + c)"
    coefficientDesignatorTuple = ("a", "b", "c")
    requiresCoefficientBoundsCheckWhenFitting = 1
    function_cpp_code = 'temp = coeff[0] * sin(coeff[1] * _id[_cwo[1]+i] + coeff[2]);'


    def Initialize(self):
        pythonequations.EquationBaseClasses.Equation2D.Initialize(self)

        try:
            nobs = len(self.IndependentDataArray[0])
            maxVal = max(self.IndependentDataArray[0])
            minVal = min(self.IndependentDataArray[0])
            self.upperCoefficientBoundsArray[1] = (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
            self.lowerCoefficientBoundsArray[1] = -1.0 * (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
        except:
            pass

    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(b * x_in + c);\n"
        return s



class SineD2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Sine D [radians]"
    _HTML = "y = a * sin(x + b)"
    coefficientDesignatorTuple = ("a", "b")
    function_cpp_code = 'temp = coeff[0] * sin(coeff[1] + _id[_cwo[1]+i]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * sin(b + x_in);\n"
        return s



class TanA2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Tangent A [radians]"
    _HTML = "y = a * tan(x)"
    LinearSSQSolverFlag = 1
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] * _id[_cwo[0]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_TanX(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * tan(x_in);\n"
        return s



class TanB2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Tangent B [radians]"
    _HTML = "y = a * tan(b*x)"
    coefficientDesignatorTuple = ("a", "b")
    requiresCoefficientBoundsCheckWhenFitting = 1
    function_cpp_code = 'temp = coeff[0] * tan(coeff[1] * _id[_cwo[0]+i]);'


    def Initialize(self):
        pythonequations.EquationBaseClasses.Equation2D.Initialize(self)

        try:
            nobs = len(self.IndependentDataArray[0])
            maxVal = max(self.IndependentDataArray[0])
            minVal = min(self.IndependentDataArray[0])
            self.upperCoefficientBoundsArray[1] = (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
            self.lowerCoefficientBoundsArray[1] = -1.0 * (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
        except:
            pass

    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * tan(b * x_in);\n"
        return s



class TanC2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Tangent C [radians]"
    _HTML = "y = a * tan(bx + c)"
    coefficientDesignatorTuple = ("a", "b", "c")
    requiresCoefficientBoundsCheckWhenFitting = 1
    function_cpp_code = 'temp = coeff[0] * tan(coeff[1] * _id[_cwo[0]+i] + coeff[2]);'


    def Initialize(self):
        pythonequations.EquationBaseClasses.Equation2D.Initialize(self)

        try:
            nobs = len(self.IndependentDataArray[0])
            maxVal = max(self.IndependentDataArray[0])
            minVal = min(self.IndependentDataArray[0])
            self.upperCoefficientBoundsArray[1] = (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
            self.lowerCoefficientBoundsArray[1] = -1.0 * (maxVal - minVal) / nobs * 6.3 * 2.0 # the "* 2.0" is to allow slack
        except:
            pass

    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])

    def VerifyCoefficientsAreWithinBounds(self, in_coeffArray):
        # see Equation base class definition of this method
        return (self.lowerCoefficientBoundsArray[1] < in_coeffArray[1] < self.upperCoefficientBoundsArray[1]) and ((self.lowerCoefficientBoundsArray[2] < in_coeffArray[2] < self.upperCoefficientBoundsArray[2]))

    def SpecificCodeCPP(self):
        s = "\ttemp = a * tan(b * x_in + c);\n"
        return s



class TanD2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Tangent D [radians]"
    _HTML = "y = a * tan(x + b)"
    coefficientDesignatorTuple = ("a", "b")
    function_cpp_code = 'temp = coeff[0] * tan(coeff[1] + _id[_cwo[1]+i]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * tan(x_in + b);\n"
        return s



class HyperbolicCosineA2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Hyperbolic Cosine A [radians]"
    _HTML = "y = a * cosh(x)"
    LinearSSQSolverFlag = 1
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] * _id[_cwo[0]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_CoshX(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * cosh(x_in);\n"
        return s



class HyperbolicCosineB2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Hyperbolic Cosine B [radians]"
    _HTML = "y = a * cosh(x + b)"
    coefficientDesignatorTuple = ("a", "b")
    function_cpp_code = 'temp = coeff[0] * cosh(_id[_cwo[0]] + coeff[1]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a * cosh(x_in + b);\n"
        return s



class HyperbolicCosineC2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Hyperbolic Cosine C [radians]"
    _HTML = "y = a / cosh(x)"
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] / _id[_cwo[0]];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_CoshX(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a / cosh(x_in);\n"
        return s



class HyperbolicCosineD2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Hyperbolic Cosine D [radians]"
    _HTML = "y = a / cosh(x + b)"
    coefficientDesignatorTuple = ("a", "b")
    function_cpp_code = 'temp = coeff[0] / cosh(_id[_cwo[0]] + coeff[1]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a / cosh(x_in + b);\n"
        return s



class HyperbolicCosineE2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Hyperbolic Cosine D [radians]"
    _HTML = "y = a / cosh(x / a)"
    coefficientDesignatorTuple = ("a")
    function_cpp_code = 'temp = coeff[0] / cosh(_id[_cwo[0]] / coeff[0]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp = a / cosh(x_in / a);\n"
        return s
